home *** CD-ROM | disk | FTP | other *** search
/ Cream of the Crop 26 / Cream of the Crop 26.iso / doom / quake.zip / HIPGRAPL.ZIP / HIPITEMS.QC < prev    next >
Text File  |  1997-02-09  |  23KB  |  886 lines

  1. /* Items QuickC program
  2.    By Jim Dose'  9/13/96
  3.    Copyright (c)1996 Hipnotic Interactive, Inc.
  4.    All rights reserved.
  5.    Do not distribute.
  6. */
  7.  
  8. float UNDERWATER = 2;
  9.  
  10. /*
  11. ===============================================================================
  12.  
  13. HIPNOTIC ITEMS
  14.  
  15. ===============================================================================
  16. */
  17. //
  18. // hip_powerup_touch function
  19. //
  20. void() hip_powerup_touch =
  21. {
  22. local entity    stemp;
  23. local float        best;
  24.  
  25.     if (other.classname != "player")
  26.         return;
  27.     if (other.health <= 0)
  28.         return;
  29.  
  30.     sprint (other, "You got the ");
  31.     sprint (other, self.netname);
  32.     sprint (other,"\n");
  33.  
  34.     if (deathmatch)
  35.     {
  36.         self.mdl = self.model;
  37.  
  38. //      if ((self.classname == "item_artifact_invulnerability") ||
  39. //         (self.classname == "item_artifact_invisibility"))
  40. //         self.nextthink = time + 60*5;
  41. //      else
  42.       self.nextthink = time + 60;
  43.  
  44.         self.think = SUB_regen;
  45.     }
  46.  
  47.     sound (other, CHAN_VOICE, self.noise, 1, ATTN_NORM);
  48.     stuffcmd (other, "bf\n");
  49.     self.solid = SOLID_NOT;
  50.    other.items2 = other.items2 | self.items2;
  51.     self.model = string_null;
  52.  
  53. // do the apropriate action
  54.    if ( self.classname == "item_artifact_wetsuit" )
  55.     {
  56.         other.wetsuit_time = 1;
  57.         other.wetsuit_finished = time + 30;
  58.     }
  59.    if ( self.classname == "item_artifact_empathy_shields" )
  60.     {
  61.       other.empathy_time = 1;
  62.       other.empathy_finished = time + 30;
  63.     }
  64.  
  65.     activator = other;
  66.     SUB_UseTargets();                // fire all targets / killtargets
  67. };
  68.  
  69.  
  70. /*QUAKED item_artifact_wetsuit (0 .5 .8) (-16 -16 -24) (16 16 32)
  71. Player takes no damage from electrical attacks and swims faster for 30 seconds
  72. */
  73. void() item_artifact_wetsuit =
  74. {
  75.    self.touch = hip_powerup_touch;
  76.  
  77.    precache_model ("progs/wetsuit.mdl");
  78.    precache_sound ("misc/wetsuit.wav");
  79.    precache_sound ("misc/weton.wav");
  80.    precache_sound ("items/suit2.wav");
  81.    self.noise = "misc/weton.wav";
  82.    setmodel (self, "progs/wetsuit.mdl");
  83.     self.netname = "Wetsuit";
  84.    self.items2 = HIP_IT_WETSUIT;
  85.    setsize (self, '-16 -16 -24', '16 16 32');
  86.  
  87.     StartItem ();
  88. };
  89.  
  90. /*
  91. ===============================================================================
  92. //
  93. // Horn of Conjuring
  94. //
  95. ===============================================================================
  96. */
  97.  
  98. void() horn_touch =
  99. {
  100.     local    float amount;
  101.    local float value;
  102.  
  103.     if (other.classname != "player")
  104.         return;
  105.  
  106.    if (deathmatch)
  107.     {
  108.         self.mdl = self.model;
  109.  
  110.       self.nextthink = time + 60;
  111.  
  112.         self.think = SUB_regen;
  113.     }
  114.  
  115.     self.solid = SOLID_NOT;
  116.     self.model = string_null;
  117.    sprint (other, "You got the Horn of Conjuring\n");
  118.    sound (other, CHAN_VOICE, self.noise, 1, ATTN_NONE);
  119.     stuffcmd (other, "bf\n");
  120.    activator = other;
  121.    horn_active = 1;
  122.    horn_charmer = other;
  123.     SUB_UseTargets();                // fire all targets / killtargets
  124.    horn_active = 0;
  125. };
  126.  
  127. /*QUAKED item_hornofconjuring (0 .5 .8) (-16 -16 0) (16 16 32)
  128. Horn of Conjuring.
  129. You must make func_spawn entities connected to this entity
  130. to spawn the charmed creature.
  131. */
  132. void() item_hornofconjuring =
  133.    {
  134.    self.touch = horn_touch;
  135.  
  136.    precache_model("progs/horn.mdl");
  137.    precache_sound("hipitems/horn.wav");
  138.    setmodel(self, "progs/horn.mdl");
  139.    self.noise = "hipitems/horn.wav";
  140.    setsize (self, '-16 -16 0', '16 16 32');
  141.     StartItem ();
  142.    };
  143.  
  144. /*QUAKED item_artifact_empathy_shields (0 .5 .8) (-16 -16 0) (16 16 32)
  145. Empathy Shield.
  146. */
  147. void() item_artifact_empathy_shields =
  148.    {
  149.    self.touch = hip_powerup_touch;
  150.  
  151.    precache_model("progs/empathy.mdl");
  152.    precache_sound("hipitems/empathy.wav");
  153.    precache_sound("hipitems/empathy2.wav");
  154.    precache_sound ("items/suit2.wav");
  155.    setmodel(self, "progs/empathy.mdl");
  156.    self.noise = "hipitems/empathy.wav";
  157.    self.netname = "Empathy Shields";
  158.    self.items2 = HIP_IT_EMPATHY_SHIELDS;
  159.    setsize (self, '-16 -16 0', '16 16 32');
  160.     StartItem ();
  161.    };
  162. /*
  163. ===============================================================================
  164.  
  165. HIPNOTIC WEAPONS
  166.  
  167. ===============================================================================
  168. */
  169.  
  170. /*QUAKED weapon_mjolnir (0 .5 .8) (-16 -16 0) (16 16 32)
  171. */
  172.  
  173. void() weapon_mjolnir =
  174. {
  175.    precache_model ("progs/g_hammer.mdl");
  176.    setmodel (self, "progs/g_hammer.mdl");
  177.     self.weapon = 3;
  178.    self.netname = "Mjolnir";
  179.    self.items = IT_MJOLNIR;
  180.     self.touch = weapon_touch;
  181.     setsize (self, '-16 -16 0', '16 16 56');
  182.     StartItem ();
  183. };
  184.  
  185. /*QUAKED weapon_laser_gun (0 .5 .8) (-16 -16 0) (16 16 32)
  186. */
  187.  
  188. void() weapon_laser_gun =
  189. {
  190.    precache_model ("progs/g_laserg.mdl");
  191.    setmodel (self, "progs/g_laserg.mdl");
  192.     self.weapon = 3;
  193.    self.netname = "Laser Cannon";
  194.    self.items = IT_LASER_CANNON;
  195.    self.touch = weapon_touch;
  196.     setsize (self, '-16 -16 0', '16 16 56');
  197.     StartItem ();
  198. };
  199.  
  200. /*QUAKED weapon_proximity_gun (0 .5 .8) (-16 -16 0) (16 16 32)
  201. */
  202.  
  203. void() weapon_proximity_gun =
  204. {
  205.    precache_model ("progs/g_prox.mdl");
  206.    setmodel (self, "progs/g_prox.mdl");
  207.     self.weapon = 3;
  208.    self.netname = "Proximity Gun";
  209.    self.items = IT_PROXIMITY_GUN;
  210.    self.touch = weapon_touch;
  211.     setsize (self, '-16 -16 0', '16 16 56');
  212.     StartItem ();
  213. };
  214.  
  215. /*
  216. ===============================================================================
  217.  
  218. HIPNOTIC HAZARDS
  219.  
  220. ===============================================================================
  221. */
  222.  
  223. void() spikemine_Home =
  224.    {
  225.    local entity head;
  226.    local entity selected;
  227.    local float cur_dist;
  228.    local float head_dist;
  229.    local vector dir, vtemp;
  230.  
  231.    self.frame = self.frame + 1;
  232.    if (self.frame==9) self.frame = 0;
  233.    self.nextthink = time + 0.2;
  234.    self.think = spikemine_Home;
  235.  
  236. // look in our immediate vicinity
  237.  
  238.    if (self.search_time < time)
  239.       {
  240.       selected = world;
  241.       cur_dist = 2000;
  242.       head = findradius(self.origin, 2000);
  243.       while(head)
  244.          {
  245.          if(!(head.flags & FL_NOTARGET) && (head.flags & FL_CLIENT))
  246.             {
  247.             if (visible(head) && (head.health > 0))
  248.                {
  249.                head_dist = vlen(head.origin-self.origin);
  250.                if (head_dist < cur_dist)
  251.                   {
  252.                   selected = head;
  253.                   cur_dist = head_dist;
  254.                   }
  255.                }
  256.             }
  257.          head = head.chain;
  258.          }
  259. //      if (selected != world && selected != self.enemy)
  260.       if (selected != world)
  261.          sound (self, CHAN_VOICE, "hipitems/spikmine.wav", 1, ATTN_NORM);
  262.       self.enemy = selected;
  263.       self.search_time = time + 1.3;
  264.       }
  265.    if (self.enemy == world)
  266.       {
  267.       sound (self, CHAN_VOICE, "misc/null.wav", 1, ATTN_NORM);
  268.       self.velocity = '0 0 0';
  269.       return;
  270.       }
  271.    vtemp = self.enemy.origin + '0 0 10';
  272.     dir = normalize(vtemp - self.origin);
  273.    if (infront(self.enemy))
  274.       {
  275.       self.velocity = dir * ((skill*50) + 50);
  276.       }
  277.    else
  278.       {
  279.       self.velocity = dir * ((skill*50) + 150);
  280.       }
  281.    };
  282.  
  283. void() spikemine_Touch =
  284.    {
  285.    if (self.health>0)
  286.       {
  287.       if (other.classname == "trap_spike_mine")
  288.          return;
  289.       if (other.classname == "missile")
  290.          return;
  291.       if (other.classname == "grenade")
  292.          return;
  293.       if (other.classname == "hiplaser")
  294.          return;
  295.       if (other.classname == "proximity_grenade")
  296.          return;
  297.  
  298.       T_Damage(self,self,self,self.health+10);
  299. //      killed_monsters = killed_monsters + 1;
  300. //      WriteByte (MSG_ALL, SVC_KILLEDMONSTER);
  301.       }
  302. //   self.effects = self.effects | EF_MUZZLEFLASH;
  303.  
  304.    T_RadiusDamage (self, self, 110, world);
  305.     sound (self, CHAN_WEAPON, "weapons/r_exp3.wav", 1, ATTN_NORM);
  306.  
  307.     WriteByte (MSG_BROADCAST, SVC_TEMPENTITY);
  308.     WriteByte (MSG_BROADCAST, TE_EXPLOSION);
  309.     WriteCoord (MSG_BROADCAST, self.origin_x);
  310.     WriteCoord (MSG_BROADCAST, self.origin_y);
  311.     WriteCoord (MSG_BROADCAST, self.origin_z);
  312.  
  313.    sound (self, CHAN_VOICE, "misc/null.wav", 1, ATTN_NORM);
  314.    self.velocity = '0 0 0';
  315.     self.touch = SUB_Null;
  316.     setmodel (self, "progs/s_explod.spr");
  317.     self.solid = SOLID_NOT;
  318.     s_explode1 ();
  319.    };
  320.  
  321. /*
  322. spike_mine_first_think
  323. */
  324.  
  325. void() spike_mine_first_think =
  326.    {
  327.    self.think = spikemine_Home;
  328.    self.nextthink = time + 0.1;
  329.    self.search_time = 0;
  330.    self.takedamage = DAMAGE_AIM;
  331.     self.use = monster_use;
  332.    };
  333.  
  334. /*QUAKED trap_spike_mine (0 .5 .8) (-16 -16 0) (16 16 32)
  335. */
  336.  
  337. void() trap_spike_mine =
  338.    {
  339.    if (deathmatch)
  340.     {
  341.         remove(self);
  342.         return;
  343.     }
  344.    precache_model ("progs/spikmine.mdl");
  345.    precache_sound ("weapons/r_exp3.wav");
  346.    precache_sound ("hipitems/spikmine.wav");
  347.    precache_sound ("misc/null.wav");
  348.    setmodel (self, "progs/spikmine.mdl");
  349. //   setmodel (self, "progs/spike.mdl");
  350.    setsize (self, self.mins, self.maxs);
  351.    self.classname = "trap_spike_mine";
  352.    self.solid = SOLID_BBOX;
  353.    self.movetype = MOVETYPE_FLYMISSILE;
  354. //   setsize (self, '0 0 0', '0 0 0');
  355. //   self.avelocity = '-100 100 -100';
  356.    self.avelocity = '-50 100 150';
  357.    if (cvar("skill") <= 1)
  358.       self.health = 200;
  359.    else
  360.       self.health = 400;
  361.    self.frame = 0;
  362.    self.think = spike_mine_first_think;
  363.    self.touch = spikemine_Touch;
  364.    self.th_die = spikemine_Touch;
  365.    self.th_stand = spikemine_Home;
  366.    self.th_walk = spikemine_Home;
  367.    self.th_run = spikemine_Home;
  368.    self.th_melee = spikemine_Home;
  369.    self.th_missile = spikemine_Home;
  370.    self.nextthink = time + 0.2;
  371.    total_monsters = total_monsters + 1;
  372.    self.flags = self.flags | FL_MONSTER;
  373.    self.deathtype = "was blasted by a spike mine";
  374.    };
  375.  
  376. //============================================================================
  377. float LIGHTNING_RANDOM = 1;
  378. float LIGHTNING_BOOM = 2;
  379.  
  380. void() SpawnLightningThink =
  381.    {
  382.    if (time > self.delay)
  383.       {
  384.       remove(self);
  385.       return;
  386.       }
  387.    self.think = SpawnLightningThink;
  388.    if (checkclient())
  389.       {
  390.       WriteByte (MSG_BROADCAST, SVC_TEMPENTITY);
  391.       WriteByte (MSG_BROADCAST, TE_LIGHTNING2);
  392.       WriteEntity (MSG_BROADCAST, self);
  393.       WriteCoord (MSG_BROADCAST, self.origin_x);
  394.       WriteCoord (MSG_BROADCAST, self.origin_y);
  395.       WriteCoord (MSG_BROADCAST, self.origin_z);
  396.       WriteCoord (MSG_BROADCAST, self.oldorigin_x);
  397.       WriteCoord (MSG_BROADCAST, self.oldorigin_y);
  398.       WriteCoord (MSG_BROADCAST, self.oldorigin_z);
  399.       }
  400.    LightningDamage(self.origin, self.oldorigin, self.lastvictim, self.dmg);
  401.    self.nextthink = time + 0.1;
  402.    };
  403.  
  404. void() trap_lightning_use =
  405.    {
  406.    local vector p1, p2;
  407.    local vector dir;
  408.    local float dst;
  409.    local float remainder;
  410.  
  411.    if (time >= self.pausetime)
  412.       {
  413.       if (self.spawnflags & LIGHTNING_BOOM)
  414.          sound (self, CHAN_AUTO, "weapons/lstart.wav", 1, ATTN_NORM);
  415.       else
  416.          sound (self, CHAN_AUTO, "weapons/lhit.wav", 1, ATTN_NORM);
  417.       if (self.classname == "trap_lightning_triggered")
  418.          self.pausetime = time + 0.1;
  419.       }
  420.    if (self.target)
  421.       {
  422.       p1 = self.origin;
  423.       p2 = self.enemy.origin;
  424.       }
  425.    else
  426.       {
  427.       makevectors (self.angles);
  428.       self.movedir = v_forward;
  429.       traceline (self.origin, self.origin + self.movedir*600, TRUE, self);
  430.       p1 = self.origin;
  431.       p2 = trace_endpos;
  432.       }
  433.    // fix up both ends of the lightning
  434.    // lightning bolts are 30 units long each
  435.    dir = normalize( p2-p1 );
  436.    dst = vlen(p2-p1);
  437.    dst = dst / 30.0;
  438.    remainder = dst - floor(dst);
  439.    if (remainder > 0)
  440.       {
  441.       remainder = remainder - 1;
  442.       // split half the remainder with the front and back
  443.       remainder = remainder * 15;
  444.       p1 = p1 + (remainder*dir);
  445.       p2 = p2 - (remainder*dir);
  446.       }
  447.    if (self.duration > 0.1)
  448.       {
  449.       local entity temp;
  450.  
  451.       temp = self;
  452.       self = spawn();
  453.       self.origin = p1;
  454.       self.oldorigin = p2;
  455.       self.lastvictim = temp;
  456.       self.dmg = temp.dmg;
  457.       self.delay = time + temp.duration;
  458.       SpawnLightningThink();
  459.       self = temp;
  460.       }
  461.    else if (checkclient())
  462.       {
  463.       WriteByte (MSG_BROADCAST, SVC_TEMPENTITY);
  464.       WriteByte (MSG_BROADCAST, TE_LIGHTNING2);
  465.       WriteEntity (MSG_BROADCAST, self);
  466.       WriteCoord (MSG_BROADCAST, p1_x);
  467.       WriteCoord (MSG_BROADCAST, p1_y);
  468.       WriteCoord (MSG_BROADCAST, p1_z);
  469.       WriteCoord (MSG_BROADCAST, p2_x);
  470.       WriteCoord (MSG_BROADCAST, p2_y);
  471.       WriteCoord (MSG_BROADCAST, p2_z);
  472.       LightningDamage(p1, p2, self, self.dmg);
  473.       }
  474.    else
  475.       LightningDamage(p1, p2, self, self.dmg);
  476.    };
  477.  
  478. void() lightning_think =
  479.    {
  480.    local float timedelay;
  481.  
  482.    if (self.state)
  483.       {
  484.       trap_lightning_use();
  485.       }
  486.    if (self.cnt == 0)
  487.       {
  488.       if (self.spawnflags & LIGHTNING_RANDOM)
  489.          {
  490.          timedelay = self.wait*random();
  491.          }
  492.       else
  493.          {
  494.          timedelay = self.wait;
  495.          }
  496.       self.cnt = 1;
  497.       self.t_length = time + self.duration - 0.1;
  498.       self.pausetime = time + self.duration - 0.1;
  499.       if (self.pausetime  < time + 0.3)
  500.          self.pausetime = time + 0.3;
  501.       if (timedelay < self.duration)
  502.          timedelay = self.duration;
  503.       self.t_width = time + timedelay;
  504.       }
  505.    if (time >= self.t_length)
  506.       {
  507.       self.cnt = 0;
  508.       self.nextthink = self.t_width;
  509.       }
  510.    else
  511.       {
  512.       self.nextthink = time + 0.2;
  513.       }
  514.    };
  515.  
  516. void() lightning_firstthink =
  517.    {
  518.    local entity targ;
  519.    if (self.target)
  520.       {
  521.       targ = find(world,targetname,self.target);
  522.       self.dest = targ.origin;
  523.       self.enemy = targ;
  524.       }
  525.    self.think = SUB_Null;
  526.    self.nextthink = 0;
  527.    if (self.classname != "trap_lightning_triggered")
  528.       {
  529.       self.nextthink = self.huntingcharmer + self.wait + self.ltime;
  530.       self.think = lightning_think;
  531.       }
  532.    };
  533.  
  534. /*QUAKED trap_lightning_triggered (0 .5 .8) (-8 -8 -8) (8 8 8) random boom
  535. When triggered, fires lightning in the direction set in QuakeEd.
  536. "wait" how long to wait between blasts (1.0 default)
  537.        if in random mode wait is multiplied by random
  538. "dmg" how much damage lightning should inflict (30 default)
  539. "duration" how long each lightning attack should last (0.1 default)
  540. */
  541.  
  542. void() trap_lightning_triggered =
  543.    {
  544.    if (self.wait == 0)
  545.       self.wait = 1.0;
  546.    if (self.dmg == 0)
  547.       self.dmg = 30;
  548.    if (self.duration == 0)
  549.       self.duration = 0.1;
  550.    self.cnt = 0;
  551.    self.use = trap_lightning_use;
  552.    precache_sound ("weapons/lhit.wav");
  553.    precache_sound ("weapons/lstart.wav");
  554.    self.huntingcharmer = self.nextthink;
  555.    self.think = lightning_firstthink;
  556.    self.nextthink = time + 0.25;
  557.    self.deathtype = "is electrocuted";
  558.    };
  559.  
  560.  
  561. /*QUAKED trap_lightning (0 .5 .8) (-8 -8 -8) (8 8 8) random boom
  562. Continuously fire lightning.
  563. "wait" how long to wait between blasts (1.0 default)
  564.        if in random mode wait is multiplied by random
  565. "nextthink" delay before firing first lightning, so multiple traps can be stagered.
  566. "dmg" how much damage lightning should inflict (30 default)
  567. "duration" how long each lightning attack should last (0.1 default)
  568. */
  569. void() trap_lightning =
  570.    {
  571.    trap_lightning_triggered ();
  572.    self.state = 1;
  573.    };
  574.  
  575. void() trap_lightning_switched_use =
  576.    {
  577.    self.state = 1 - self.state;
  578.    if (self.state == 1)
  579.       self.nextthink = self.huntingcharmer;
  580.    };
  581. /*QUAKED trap_lightning_switched (0 .5 .8) (-8 -8 -8) (8 8 8) random boom
  582. Continuously fires lightning.
  583. "wait" how long to wait between blasts (1.0 default)
  584.        if in random mode wait is multiplied by random
  585. "nextthink" delay before firing first lightning, so multiple traps can be stagered.
  586. "dmg" how much damage lightning should inflict (30 default)
  587. "duration" how long each lightning attack should last (0.1 default)
  588. "state" 0 (default) initially off, 1 initially on.
  589. */
  590. void() trap_lightning_switched =
  591.    {
  592.    trap_lightning_triggered ();
  593.    self.use = trap_lightning_switched_use;
  594.    };
  595.  
  596.  
  597. entity tesla_target;
  598. float tesla_numtargets;
  599. void() trap_tesla_scan =
  600.    {
  601.    local entity head;
  602.    local entity prev;
  603.  
  604. // look in our immediate vicinity
  605.  
  606.    tesla_numtargets = 0;
  607.    head = findradius(self.origin, self.distance);
  608.    while(head)
  609.       {
  610.       if(!(head.flags & FL_NOTARGET) && (head.flags & self.cnt))
  611.          {
  612.          if (visible(head) && (head.health > 0) && (head.struck_by_mjolnir==0))
  613.             {
  614.             if (tesla_numtargets == 0)
  615.                {
  616.                tesla_target = head;
  617.                }
  618.             else
  619.                {
  620.                prev.next_ent = head;
  621.                }
  622.             tesla_numtargets = tesla_numtargets + 1;
  623.             prev = head;
  624.             if (tesla_numtargets==self.count)
  625.                return;
  626.             }
  627.          }
  628.       head = head.chain;
  629.       }
  630.    };
  631.  
  632. void() TeslaLightningThink =
  633.    {
  634.    self.owner.attack_state = 2;
  635.    if (time > self.delay)
  636.       {
  637.       self.enemy.struck_by_mjolnir = 0;
  638.       remove(self);
  639.       return;
  640.       }
  641.    traceline (self.origin, self.enemy.origin, TRUE, self);
  642.  
  643.    if (trace_fraction != 1.0 || self.enemy.health<=0 || vlen(self.origin-self.enemy.origin) > (self.distance+10))
  644.       {
  645.       self.enemy.struck_by_mjolnir = 0;
  646.       remove(self);
  647.       return;
  648.       }
  649.    WriteByte (MSG_BROADCAST, SVC_TEMPENTITY);
  650.    WriteByte (MSG_BROADCAST, TE_LIGHTNING2);
  651.    WriteEntity (MSG_BROADCAST, self);
  652.    WriteCoord (MSG_BROADCAST, self.origin_x);
  653.    WriteCoord (MSG_BROADCAST, self.origin_y);
  654.    WriteCoord (MSG_BROADCAST, self.origin_z);
  655.    WriteCoord (MSG_BROADCAST, trace_endpos_x);
  656.    WriteCoord (MSG_BROADCAST, trace_endpos_y);
  657.    WriteCoord (MSG_BROADCAST, trace_endpos_z);
  658.    LightningDamage(self.origin, trace_endpos, self.lastvictim, self.dmg);
  659.    self.nextthink = time + 0.1;
  660.    };
  661.  
  662. void(entity targ) SpawnTeslaLightning =
  663.    {
  664.    local entity lgt;
  665.    // spawn actual lightning
  666.    lgt = spawn();
  667.    if (self.duration>0)
  668.       {
  669.       lgt.delay = time + self.duration;
  670.       }
  671.    else
  672.       {
  673.       lgt.delay = time + 9999;
  674.       }
  675.    lgt.enemy = targ;
  676.    targ.struck_by_mjolnir = 1;
  677.    lgt.distance = self.distance;
  678.    lgt.owner = self;
  679.    lgt.lastvictim = self.lastvictim;
  680.    lgt.dmg = self.dmg;
  681.    lgt.origin = self.origin;
  682.    lgt.think = TeslaLightningThink;
  683.    lgt.nextthink = time;
  684.    lgt.deathtype = self.deathtype;
  685.    };
  686.  
  687. void() trap_tesla_think =
  688.    {
  689.    if (self.state == 0)
  690.       {
  691.       self.nextthink = time + 0.25;
  692.       return;
  693.       }
  694.    if (self.attack_state == 0)
  695.       {
  696.       self.think = trap_tesla_think;
  697.       trap_tesla_scan();
  698.       if (tesla_numtargets > 0)
  699.          {
  700.          if (self.wait > 0)
  701.             sound (self, CHAN_AUTO, "misc/tesla.wav", 1, ATTN_NORM);
  702.          self.attack_state = 1;
  703.          self.nextthink = time + self.wait;
  704.          return;
  705.          }
  706.       self.nextthink = time + 0.25;
  707.       if (self.delay > 0)
  708.          {
  709.          if (time > self.search_time)
  710.             {
  711.             self.attack_state = 3;
  712.             }
  713.          }
  714.       }
  715.    else if (self.attack_state == 1)
  716.       {
  717.       trap_tesla_scan();
  718.       while (tesla_numtargets > 0)
  719.          {
  720.          sound (self, CHAN_AUTO, "hipweap/mjolhit.wav", 1, ATTN_NORM);
  721.          SpawnTeslaLightning (tesla_target);
  722.          tesla_target = tesla_target.next_ent;
  723.          tesla_numtargets = tesla_numtargets - 1;
  724.          }
  725.       self.attack_state = 2;
  726.       self.nextthink = time + 1;
  727.       }
  728.    else if (self.attack_state == 2)
  729.       {
  730.       self.attack_state = 3;
  731.       self.nextthink = time + 0.2;
  732.       }
  733.    else if (self.attack_state == 3)
  734.       {
  735.       self.attack_state = 0;
  736.       self.nextthink = time + 0.1;
  737.       if (self.classname == "trap_gods_wrath")
  738.          {
  739.          self.nextthink = -1;
  740.          }
  741.       }
  742.    };
  743.  
  744. /*QUAKED trap_tesla_coil (0 .5 .8) (-8 -8 -8) (8 8 8) targetenemies
  745. targets enemies in vicinity and fires at them
  746. "wait" how long build up should be (2 second default)
  747. "dmg" how much damage lightning should inflict (2 + 5*skill default)
  748. "duration" how long each lightning attack should last (continuous default)
  749. "distance" how far the tesla coil should reach (600 default)
  750. "state" on/off for the coil (0 default is off)
  751. "count" number of people to target (2 default)
  752. */
  753. void() trap_tesla_coil =
  754.    {
  755.    precache_sound ("misc/tesla.wav");
  756.    precache_sound ("hipweap/mjolhit.wav");   // lightning sound
  757.    if (self.wait == 0)
  758.       self.wait = 2;
  759.    if (self.dmg == 0)
  760.       self.dmg = 2 + (5*cvar("skill"));
  761.    if (self.duration == 0)
  762.       self.duration = -1;
  763.    if (self.distance == 0)
  764.       self.distance = 600;
  765.    if (self.spawnflags & 1)
  766.       self.cnt = FL_CLIENT | FL_MONSTER;
  767.    else
  768.       self.cnt = FL_CLIENT;
  769.    self.use = trap_lightning_switched_use;
  770.    if (self.delay == 0)
  771.       self.delay = -1;
  772.    self.nextthink = time + random();
  773.    self.think = trap_tesla_think;
  774.    self.lastvictim = world;
  775.    tesla_numtargets = 0;
  776.    self.attack_state = 0;
  777.    self.deathtype = "is electrocuted";
  778.    };
  779.  
  780. void() trap_gods_wrath_use =
  781.    {
  782.    if (self.attack_state==0)
  783.       {
  784.       self.search_time = time + self.delay;
  785.       self.lastvictim = activator;
  786.       trap_tesla_think();
  787.       }
  788.    };
  789.  
  790. /*QUAKED trap_gods_wrath (0 .5 .8) (-8 -8 -8) (8 8 8) targetenemies
  791. targets enemies in vicinity and fires at them
  792. "dmg" how much damage lightning should inflict (5 default)
  793. "duration" how long each lightning attack should last (continuous default)
  794. "distance" how far god's wrath should reach (600 default)
  795. "delay" how long to wait until god calms down
  796.    this is only needed if no one is targetted (5 seconds default)
  797. "count" number of people to target (2 default)
  798. */
  799. void() trap_gods_wrath =
  800.    {
  801.    if (self.delay == 0)
  802.       self.delay = 5;
  803.    trap_tesla_coil();
  804.    self.wait = 0;
  805.    self.state = 1;
  806.    self.nextthink = -1;
  807.    self.deathtype = "suffers the wrath of God";
  808. //   self.attack_state = 1;
  809.    self.use = trap_gods_wrath_use;
  810.    };
  811.  
  812. void() trap_gravity_touch =
  813.    {
  814.    if ( self.attack_finished > time )
  815.       return;
  816.  
  817.    if (other.takedamage)
  818.       {
  819.       T_Damage (other, self, self, self.dmg );
  820.       self.attack_finished = time + 0.2;
  821.       }
  822.    };
  823.  
  824. void() trap_gravity_think =
  825.    {
  826.    local vector vel;
  827.    local vector dir;
  828.    local vector delta;
  829.  
  830.    self.ltime = time;
  831.    trap_tesla_scan();
  832.    while (tesla_numtargets > 0)
  833.       {
  834.       delta = self.origin - tesla_target.origin;
  835.       dir = normalize( delta );
  836.       vel = dir * self.speed;
  837.       if ( ( tesla_target.wetsuit_finished > time ) &&
  838.          ( self.spawnflags & UNDERWATER ) )
  839.          {
  840.          vel = vel * 0.6;
  841.          }
  842.  
  843.       tesla_target.velocity = tesla_target.velocity + vel;
  844.       tesla_target = tesla_target.next_ent;
  845.       tesla_numtargets = tesla_numtargets - 1;
  846.       }
  847.    self.nextthink = time + 0.1;
  848.    };
  849.  
  850. /*QUAKED trap_gravity_well (.8 .5 0) (-8 -8 -8) (8 8 8) targetenemies UNDERWATER
  851. targets enemies in vicinity and draws them near, gibbing them on contact.
  852.  
  853. UNDERWATER cuts the pull in half for players wearing the wetsuit
  854.  
  855. "distance" how far the gravity well should reach (600 default)
  856. "count" number of people to target (2 default)
  857. "speed" is how strong the pull is. (210 default)
  858. "dmg" is how much damage to do each touch. (10000 default)
  859. */
  860. void() trap_gravity_well =
  861.    {
  862.    self.solid = SOLID_TRIGGER;
  863.    self.movetype = MOVETYPE_NONE;
  864.    setsize( self, '-16 -16 -16','16 16 16');
  865.    if ( self.dmg == 0 )
  866.       {
  867.       self.dmg = 10000;
  868.       }
  869.    if ( self.speed == 0 )
  870.       self.speed = 210;
  871.    if (self.distance == 0)
  872.       self.distance = 600;
  873.    if (self.spawnflags & 1)
  874.       self.cnt = FL_CLIENT | FL_MONSTER;
  875.    else
  876.       self.cnt = FL_CLIENT;
  877.  
  878.    self.attack_finished = 0;
  879.    self.think = trap_gravity_think;
  880.    self.touch = trap_gravity_touch;
  881.    self.lastvictim = world;
  882.    tesla_numtargets = 0;
  883.    self.nextthink = time + 0.1;
  884.    self.ltime = time;
  885.    };
  886.